Skip to content

Add github_repository backend for direct repository access [model slop POC, don't review] - #307

Open
hosom wants to merge 6 commits into
mainfrom
github-repository-backend
Open

hosom wants to merge 6 commits into
mainfrom
github-repository-backend

Conversation

@hosom

@hosom hosom commented Sep 24, 2026 •

Copy link
Copy Markdown
Contributor

This pull request adds support for GitHub repositories as a "backend" for the GitHub plugin.

One of the most noteworthy parts of this pull request is that it supports using a GH App as the credential, which can be supplied separately in the configuration.

I'll fill in this PR body with additional details, but for more information, see the README.md modifications in the PR.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b0e8ea9-7fd3-4e74-87d7-c3b7e69d8a7b
Copilot AI balanced review requested due to automatic review settings September 24, 2026 20:47
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b0e8ea9-7fd3-4e74-87d7-c3b7e69d8a7b

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copilot review overview

🟡 Changes recommended

Membership snapshots, incomplete permission sources, and pending invitations currently undermine fail-closed reconciliation.

Get a fresh assessment by requesting another Copilot review.

Review effort: Balanced
Findings: 2 High severity · 1 Medium severity

Open (3)
What changed in this PR

Adds a backend for managing direct, role-aware GitHub repository access.

Changes:

  • Loads validated repository role files.
  • Reconciles direct grants through GraphQL and REST.
  • Adds comprehensive tests and rollout documentation.
File Description
README.md Documents configuration and rollout.
lib/​entitlements/​backend/​github_repository.rb Defines and loads the backend.
lib/​entitlements/​backend/​github_repository/​configuration.rb Validates and loads role files.
lib/​entitlements/​backend/​github_repository/​controller.rb Coordinates reconciliation.
lib/​entitlements/​backend/​github_repository/​models/​repository_access.rb Models role-aware access.
lib/​entitlements/​backend/​github_repository/​provider.rb Calculates repository changes.
lib/​entitlements/​backend/​github_repository/​service.rb Implements GitHub reads and mutations.
spec/​unit/​entitlements/​backend/​github_repository_spec.rb Tests backend behavior.
spec/​unit/​spec_helper.rb Loads the backend in tests.
spec/​unit/​fixtures/​repositories/​other.repo/​maintain.txt Adds group-rule fixture.
spec/​unit/​fixtures/​repositories/​other.repo/​admin.yaml Adds expired-rule fixture.
spec/​unit/​fixtures/​repositories/​entitlements-app/​write.rb Adds Ruby-rule fixture.
spec/​unit/​fixtures/​repositories/​entitlements-app/​triage.yaml Adds YAML-rule fixture.
spec/​unit/​fixtures/​repositories/​entitlements-app/​read.txt Adds text-rule fixture.

💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.

Comment on lines +40 to +42
def apply(repository, instructions)
Configuration.validate_repository!(repository)
instructions.sort_by { |instruction| [instruction.fetch(:action) == :upsert ? 0 : 1, instruction.fetch(:login).downcase] }.each do |instruction|
Comment on lines +132 to +137
if status == 201
unless result.is_a?(Sawyer::Resource) && result[:id].is_a?(Integer) && result[:id] > 0
GitHubRepository.fail!("Malformed repository invitation response")
end
Entitlements.logger.warn("#{repository}: invitation created for #{instruction.fetch(:login)}; access is not yet active")
end
Comment on lines +86 to +88
unless edge.is_a?(Hash) && edge["node"].is_a?(Hash) && edge["permissionSources"].is_a?(Array)
GitHubRepository.fail!("Missing or malformed repository permission sources")
end
@hosom hosom changed the title Add github_repository backend for direct repository access Add github_repository backend for direct repository access [model slop POC, don't review] Sep 24, 2026
@hosom

hosom commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

The vendored-gem demo is available in github/entitlements#142229 (draft, DO NOT MERGE). It pins preview version 1.2.6.pre.repository.gc8c3584339bf from commit c8c3584339bf, adds github/entitlements-app role data, and exercises actual configuration → packaged backend → paginated GraphQL/REST simulation → no-op convergence. The full entitlements suite passes locally (223 examples, 0 failures, 8 existing pending). Live reads remain blocked by the available OAuth token lacking admin:org for permissionSources/roleName; no live mutations were made.

The live entitlements-default demo proved edge.permission adds a public_repo scope requirement to an admin:org token. Read only the source-specific roles consumed by reconciliation, without broadening credentials or falling back to effective permissions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 5b0e8ea9-7fd3-4e74-87d7-c3b7e69d8a7b
@hosom

hosom commented Sep 24, 2026

Copy link
Copy Markdown
Contributor Author

The real github/entitlements#142229 no-op calculation exposed an unnecessary credential requirement in the initial query: effective edge.permission requires public_repo, while CI has admin:org. Commit d12e39a removes that unused field, retaining exact direct permissionSources.roleName and strict error handling. No token scopes were broadened. A regression test guards the requested fields; all 285 plugin examples pass with 100% line coverage. The demo now vendors the refreshed source-commit-derived gem and is rerunning the actual entitlements-default calculation. No live mutations or merge are involved.

Remove all repository team associations and undeclared direct grants, including outside collaborators. Preserve team hierarchy and membership, order user upserts before cleanup, and verify snapshots before and after application.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a8107bce-2500-45f8-b046-3f50092d9fbd
@hosom

hosom commented Sep 25, 2026

Copy link
Copy Markdown
Contributor Author

Published individual-only repository reconciliation in 224de61218a0721768b5c37c338f8a25aa88198c and rebuilt the preview for github/entitlements#142229.

The live read-only App no-op run succeeded and now proposes removal of github/sae-iam, github/sae-iam-reviewers, and github/sae-reviewers from entitlements-app: https://github.com/github/entitlements/actions/runs/36142358100/job/108095019791. No live mutations were made.

Production gate discovered: the declared user currently has organization-owner JIT access and the backend rejects desired owners. The demo uses the existing warn-and-skip setting to verify team cleanup, not as a production fix. Owner declarations/direct-grant persistence during JIT elevation need an explicit policy and API validation before rollout. This live run does not verify owner grant creation or applied convergence.

hosom and others added 2 commits September 25, 2026 10:38
Discover base permissions and every organization role and assignment. Accept owners as desired users, defer ambiguous owner grants and roles below inherited access, and preserve organization/enterprise team sources using access_source. Refresh organization access for stale-plan and convergence checks, fail closed on incomplete metadata, and document required read permissions and policy exceptions.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: a8107bce-2500-45f8-b046-3f50092d9fbd
@@ -0,0 +1,86 @@
# frozen_string_literal: true

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Organization grants will show up in the access list for the Repository. Because the API represents your highest level of highest issued access, we need to reconcile who has access from Organization access, or we will try and fail to add Org Administrators to any repo they are given a direct entitlement for. This is also in play during JIT access, complicating matters even more, as in some runs a user will appear as a Repository Owner issued as an Organization grant and in other runs they will have their normal individually issued access.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants